<template>
    <div class="smart-table-container" ref="containerRef">
        <el-table :data="filteredData" :loading="loading" :height="height" :max-height="maxHeight" :stripe="stripe"
            :border="border" :size="size" :fit="true" table-layout="auto" style="width: 100%">
            <el-table-column v-if="showSelection" type="selection" width="55" align="center" fixed="left" />
            <el-table-column v-if="showIndex" type="index" label="序号" width="80" align="center" fixed="left" />

            <el-table-column v-for="col in computedColumns" :key="col.key" :prop="col.key"
                :label="col.label || col.title" :width="getColumnWidth(col)" :min-width="getColumnMinWidth(col)"
                :fixed="col.fixed" :sortable="col.sortable ? 'custom' : false"
                :show-overflow-tooltip="col.showOverflowTooltip !== false" :align="col.align || 'left'"
                :header-align="col.headerAlign || col.align || 'left'">
                <template #header>
                    <div class="th-with-filter">
                        <span>{{ col.label || col.title }}</span>
                        <el-popover v-if="col.filterable" placement="bottom" trigger="manual" width="300"
                            :visible="openedFilterKey === col.key">
                            <template #reference>
                                <el-button link type="primary" class="filter-btn" @click.stop="toggleFilter(col.key)">
                                    <el-icon>
                                        <Filter />
                                    </el-icon>
                                </el-button>
                            </template>
                            <SmartFilter v-model="activeFilters[col.key]" :type="normalizeType(col.type)"
                                :options="getOptionsForColumn(col)" @apply="onFilterApply(col.key)"
                                @clear="onFilterClear(col.key)" />
                        </el-popover>
                    </div>
                </template>

                <template #default="{ row, $index }">
                    <div v-if="col.render" v-html="col.render(row, $index)"></div>
                    <el-tag v-else-if="col.type === 'tag'" :type="getTagType(row[col.key], col.tagConfig)"
                        :size="col.tagSize || 'small'" :effect="col.tagEffect || 'light'">
                        {{ row[col.key] }}
                    </el-tag>
                    <el-link v-else-if="col.type === 'link'" :type="col.linkType || 'primary'"
                        :underline="col.underline !== false" @click="handleLinkClick(row, col, $index)">
                        {{ row[col.key] }}
                    </el-link>
                    <span v-else>{{ row[col.key] }}</span>
                </template>
            </el-table-column>

            <el-table-column v-if="actions && actions.length > 0" label="操作" :width="actionColumnWidth"
                :fixed="actionColumnFixed" align="center">
                <template #default="{ row, $index }">
                    <el-button v-for="action in actions" :key="action.key" :type="action.type || 'primary'"
                        :size="action.size || 'small'" :plain="action.plain" :round="action.round"
                        :circle="action.circle" :disabled="action.disabled && action.disabled(row)"
                        @click="handleAction(action, row, $index)">
                        {{ action.label }}
                    </el-button>
                </template>
            </el-table-column>
        </el-table>

        <div v-if="showPagination" class="pagination-container">
            <el-pagination :current-page="currentPage" :page-size="pageSize" :page-sizes="pageSizes" :total="total"
                :layout="paginationLayout" :background="paginationBackground" @size-change="handleSizeChange"
                @current-change="handleCurrentChange" />
        </div>
    </div>
</template>

<script setup lang="ts">
import { reactive, computed, onMounted, onBeforeUnmount, ref } from 'vue'
import { Filter } from '@element-plus/icons-vue'
import SmartFilter from './SmartFilter.vue'

const props = defineProps({
    columns: { type: Array, required: true },
    data: { type: Array, required: true },
    loading: { type: Boolean, default: false },
    height: { type: [String, Number], default: undefined },
    maxHeight: { type: [String, Number], default: undefined },
    stripe: { type: Boolean, default: false },
    border: { type: Boolean, default: true },
    size: { type: String, default: 'default' },
    showSelection: { type: Boolean, default: false },
    showIndex: { type: Boolean, default: false },
    showPagination: { type: Boolean, default: false },
    actions: { type: Array, default: () => [] },
    actionColumnWidth: { type: [String, Number], default: 150 },
    actionColumnFixed: { type: [String, Boolean], default: 'right' },
    currentPage: { type: Number, default: 1 },
    pageSize: { type: Number, default: 10 },
    pageSizes: { type: Array, default: () => [10, 20, 50, 100] },
    total: { type: Number, default: 0 },
    paginationLayout: { type: String, default: 'total, sizes, prev, pager, next, jumper' },
    paginationBackground: { type: Boolean, default: true },
})

const emit = defineEmits(['action', 'size-change', 'current-change', 'link-click'])

const computedColumns = computed(() => props.columns.map(col => ({ ...col, label: col.label || col.title })))

// 自定义筛选状态
const activeFilters = reactive({})
// 记录当前打开筛选框的列 key
const openedFilterKey = ref('')

const normalizeType = t => (t === 'date' || t === 'datetime' ? 'date' : 'string')

const getOptionsForColumn = col => {
    if (normalizeType(col.type) === 'date') return []
    const set = new Set((props.data || []).map(r => r[col.key]).filter(v => v !== undefined && v !== null))
    return [...set].map(v => ({ text: v, value: v }))
}

const applies = {
    string: (rowVal, filterVal) => (filterVal == null || filterVal === '' ? true : rowVal === filterVal),
    date: (rowVal, range) => {
        if (!range || !Array.isArray(range) || range.length < 2) return true
        if (!rowVal) return false
        const rowDate = new Date(String(rowVal).includes(' ') ? String(rowVal).split(' ')[0] : rowVal)
        const start = new Date(range[0])
        const end = new Date(range[1])
        start.setHours(0, 0, 0, 0)
        end.setHours(23, 59, 59, 999)
        return rowDate >= start && rowDate <= end
    }
}

const filteredData = computed(() => {
    const rows = Array.isArray(props.data) ? props.data : []
    return rows.filter(row => {
        return computedColumns.value.every(col => {
            if (!col.filterable) return true
            const t = normalizeType(col.type)
            const fn = applies[t]
            return fn ? fn(row[col.key], activeFilters[col.key]) : true
        })
    })
})

// 监听容器宽度，按实时宽度均分列，增强自适应
const containerRef = ref(null)
const autoMinWidth = ref(160)

onMounted((): void => {
    const update = () => {
        const el = containerRef.value as unknown as HTMLElement
        if (!el) return
        const width = el.clientWidth || 0
        const totalCols = computedColumns.value.length || 1
        // 分配时考虑内边距与滚动条，留出余量 24
        const approx = Math.floor((width - 24) / totalCols)
        autoMinWidth.value = Math.min(Math.max(approx, 140), 280)
    }
    update()
    const ro = new ResizeObserver(update)
    containerRef.value && ro.observe(containerRef.value)
})

// 若表列较少，动态增加列的最小宽度使其横向拉伸以填满表格
const getColumnMinWidth = (col) => {
    if (col.minWidth) return col.minWidth
    return autoMinWidth.value
}

// 列宽策略：
// - 默认不固定 width，使用 minWidth 以允许列拉伸填满容器
// - 若列设置 fixedWidth=true，则尊重 col.width 作为固定宽度
const getColumnWidth = (col) => {
    if (col.fixedWidth === true && col.width) return col.width
    return undefined
}

const toggleFilter = key => {
    openedFilterKey.value = openedFilterKey.value === key ? '' : key
}

const onFilterApply = key => () => {
    // 应用后收起弹层
    openedFilterKey.value = ''
}
const onFilterClear = key => () => {
    activeFilters[key] = null
    openedFilterKey.value = ''
}

// 仅保留：点击非筛选区域自动关闭筛选框
const handleDocumentClick = (e: MouseEvent) => {
    if (!openedFilterKey.value) return
    const target = e.target as HTMLElement
    const inBtn = target.closest ? target.closest('.filter-btn') : null
    const inPop = target.closest ? target.closest('.el-popper') : null
    if (inBtn || inPop) return
    openedFilterKey.value = ''
}

onMounted(() => document.addEventListener('click', handleDocumentClick))
onBeforeUnmount(() => document.removeEventListener('click', handleDocumentClick))

const onPopoverVisibleChange = (key, visible) => {
    openedFilterKey.value = visible ? key : ''
}

const getTagType = (value, tagConfig) => (tagConfig?.typeMap?.[value] ? tagConfig.typeMap[value] : 'info')

const handleAction = (action, row, index) => {
    action.handler?.(row, index)
    emit('action', action.key, row, index)
}
const handleLinkClick = (row, col, index) => emit('link-click', row, col, index)
const handleSizeChange = size => emit('size-change', size)
const handleCurrentChange = page => emit('current-change', page)
</script>

<style scoped>
.smart-table-container {
    width: 100%;
}

.pagination-container {
    display: flex;
    justify-content: flex-end;
    margin-top: 16px;
    padding: 0 16px;
}

.th-with-filter {
    display: flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

.filter-btn {
    padding: 0 2px;
}

/* 让弹出的筛选框在触发按钮正下方居中视觉更稳定 */
:deep(.el-popper) {
    transform-origin: top center !important;
}

/* 让列较少时自动撑满容器，避免右侧空白 */
:deep(.el-table__body),
:deep(.el-table__header) {
    table-layout: auto;
}
</style>
